package cn.quang.search.admin.service.impl;

import cn.quang.search.admin.entity.dto.Operator;
import cn.quang.search.admin.entity.dto.Result;
import cn.quang.search.admin.entity.po.EntityDataSource;
import cn.quang.search.admin.entity.po.EntityTable;
import cn.quang.search.admin.entity.vo.datasource.DataSourceRequest;
import cn.quang.search.admin.entity.vo.datasource.TestConnectionRequest;
import cn.quang.search.admin.entity.vo.table.TableDataSourceTreeVO;
import cn.quang.search.admin.enums.EntityDataSourceTypeEnum;
import cn.quang.search.admin.mapper.EntityDataSourceMapper;
import cn.quang.search.admin.mapper.EntityTableMapper;
import cn.quang.search.admin.service.IDBMetaService;
import cn.quang.search.admin.service.IEntityDataSourceService;
import cn.quang.search.admin.service.ISearchConfigChangeService;
import cn.quang.search.admin.service.common.RedisService;
import cn.quang.search.admin.utils.AssertUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author:  Entity Generator
 * @since:  2024-02-27 17:43:11
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class EntityDataSourceService implements IEntityDataSourceService {

	private final EntityDataSourceMapper entityDataSourceMapper;
	private final EntityTableMapper entityTableMapper;
	private final IDBMetaService dbMetaService;
	private final ISearchConfigChangeService searchConfigChangeService;
	private final RedisService redisService;

	private static final String DATA_SOURCE_UNIQUE_LOCK = "CRM3$ENTITY_DATA_SOURCE_ADD$";
	private static final int EXPIRE_ONE_MINUTE = 60;
	private static final int DEFAULT_INITIAL_SIZE = 5;
	private static final int DEFAULT_MAX_ACTIVE_SIZE = 20;
	private static final int DEFAULT_MIN_IDLE_SIZE = 5;
	private static final int DEFAULT_TIMEOUT_MILLISECOND = 3000;

	/**
	 * 列表查询
	 * @param operator 操作人
	 * @param request 请求
	 */
//	@Override
//	public Result<Pagination<DataSourceListItemVO>> list4View(Operator operator, DataSourceQueryRequest request) {
//		Result<Pagination<DataSourceListItemVO>> Result = new Result<>();
//
//		SearchGroup searchGroup = new SearchGroup(SearchLogicType.AND);
//		if(StringUtils.isNotBlank(request.getName())){
//			searchGroup.addSearch(EntityDataSource.COL_NAME, SearchOperator.Equal, request.getName());
//		}
//		if(StringUtils.isNotBlank(request.getStartCreateTime())){
//			Date startCreateTime = DateUtil.parse(request.getStartCreateTime(), DateUtil.PATTERN_FULL);
//			searchGroup.addSearch(EntityDataSource.COL_CREATE_TIME, SearchOperator.GreaterThanOrEqual, startCreateTime);
//		}
//		if(StringUtils.isNotBlank(request.getEndCreateTime())){
//			Date endCreateTime = DateUtil.parse(request.getEndCreateTime(), DateUtil.PATTERN_FULL);
//			searchGroup.addSearch(EntityDataSource.COL_CREATE_TIME, SearchOperator.LessThan, endCreateTime);
//		}
//		try {
//			Pagination<EntityDataSource> entitiesPagination = this.entityDataSourceDao.findEntitiesPagination(null, searchGroup, request.getPageIndex(), request.getPageSize(), String.format("%s desc", EntityDataSource.COL_CREATE_TIME));
//			Pagination<DataSourceListItemVO> pagination = new Pagination<>(request.getPageIndex(), request.getPageSize(), entitiesPagination.getTotalCount());
//			if(CollectionUtils.isNotEmpty(entitiesPagination)) {
//				for (EntityDataSource entityDataSource : entitiesPagination) {
//					pagination.add(convertToListItemVo(entityDataSource));
//				}
//			}
//			return Result.changeSucc(pagination);
//		} catch (Exception e) {
//			logger.error("数据源查询失败", e);
//			return Result.changeErr("查询失败");
//		}
//	}

//	/**
//	 * 查询详情
//	 * @param operator 操作人
//	 * @param dataSourceId 数据源ID
//	 */
//	@Override
//	public Result<DataSourceDetailVO> detail4View(Operator operator, long dataSourceId) {
//		Result<DataSourceDetailVO> Result = new Result<>();
//		try {
//			EntityDataSource entity = entityDataSourceDao.findEntityById(dataSourceId);
//			return Result.changeSucc(convertToDetailVo(entity));
//		} catch (Exception e) {
//			logger.error(String.format("数据源(%s)查询失败", dataSourceId), e);
//			return Result.changeErr("数据源详情查询失败");
//		}
//	}

//	/**
//	 * 转换成VO对象(编辑页)
//	 * @param entityDataSource 数据源实体
//	 * @return VO视图类
//	 */
//	private DataSourceDetailVO convertToDetailVo(EntityDataSource entityDataSource) {
//		if (entityDataSource == null) {
//			return null;
//		}
//		DataSourceDetailVO dataSourceDetailVO = new DataSourceDetailVO();
//		dataSourceDetailVO.setId(entityDataSource.getId());
//		dataSourceDetailVO.setName(entityDataSource.getName());
//		dataSourceDetailVO.setDescription(entityDataSource.getDescription());
//		dataSourceDetailVO.setType(entityDataSource.getType());
//		dataSourceDetailVO.setJdbcUrl(entityDataSource.getJdbcUrl());
//		dataSourceDetailVO.setUserName(entityDataSource.getUserName());
//		dataSourceDetailVO.setPassword(entityDataSource.getPassword());
//		dataSourceDetailVO.setMinIdleSize(entityDataSource.getMinIdleSize());
//		dataSourceDetailVO.setInitialSize(entityDataSource.getInitialSize());
//		dataSourceDetailVO.setMaxActiveSize(entityDataSource.getMaxActiveSize());
//		dataSourceDetailVO.setTimeoutMillisecond(entityDataSource.getTimeoutMillisecond());
//
//		return dataSourceDetailVO;
//	}

//	/**
//	 * 转换成VO对象(列表页)
//	 * @param entityDataSource 数据源实体
//	 * @return VO视图类
//	 */
//	private DataSourceListItemVO convertToListItemVo(EntityDataSource entityDataSource) {
//		DataSourceListItemVO vo = new DataSourceListItemVO();
//		vo.setId(entityDataSource.getId());
//		vo.setName(entityDataSource.getName());
//		vo.setDescription(entityDataSource.getDescription());
//		EntityDataSourceTypeEnum typeEnum = EntityDataSourceTypeEnum.of(entityDataSource.getType());
//		vo.setTypeName(typeEnum == null ? "N/A" : typeEnum.getName());
//		String connection;
//		if(typeEnum == EntityDataSourceTypeEnum.ES){
//			connection = "tcp://crmSearchCenter/SearchIndexService";
//		}else{
//			connection = entityDataSource.getJdbcUrl();
//		}
//		vo.setConnection(connection);
//		vo.setCreatorName(BspService.getBspUserNameById(entityDataSource.getCreatorId()));
//		vo.setCreateTimeFormat(DateUtil.format(entityDataSource.getCreateTime()));
//		vo.setModifierName(BspService.getBspUserNameById(entityDataSource.getModifierId()));
//		vo.setModifyTimeFormat(DateUtil.format(entityDataSource.getModifyTime()));
//		return vo;
//	}

	/**
	 * 新增数据源
	 * @param operator 操作人
	 * @param request 新增请求
	 * @return 添加结果
	 */
	@Override
	public Result<Long> add(Operator operator, DataSourceRequest request){
		Result<Long> methodResult = new Result<>();
		AssertUtils.argumentBlank(request.getName(), "必须提供数据源标识(唯一)");

		int dataSourceType = request.getType();

		if(dataSourceType == EntityDataSourceTypeEnum.MYSQL.getCode()){
			AssertUtils.argumentBlank(request.getJdbcUrl(), "MySQL数据源必须提供JDBC URL");
			AssertUtils.argumentBlank(request.getUserName(), "MySQL数据源必须提供用户名");
			AssertUtils.argumentBlank(request.getPassword(), "MySQL数据源必须提供密码");
			if(request.getInitialSize() == 0)			{ request.setInitialSize(DEFAULT_INITIAL_SIZE); 				}
			if(request.getMaxActiveSize() == 0)			{ request.setMaxActiveSize(DEFAULT_MAX_ACTIVE_SIZE); 			}
			if(request.getMinIdleSize() == 0)			{ request.setMinIdleSize(DEFAULT_MIN_IDLE_SIZE); 				}
			if(request.getTimeoutMillisecond() == 0)	{ request.setTimeoutMillisecond(DEFAULT_TIMEOUT_MILLISECOND); 	}
		}
		String dataSourceName = request.getName();
		String uniqueKey = DATA_SOURCE_UNIQUE_LOCK + dataSourceName;
		String requestId = UUID.randomUUID().toString();
		if(redisService.tryLock(uniqueKey, requestId, EXPIRE_ONE_MINUTE)){
			try {
				EntityDataSource dataSource = entityDataSourceMapper.selectByName(dataSourceName);
				if(dataSource != null){
					return methodResult.changeErr("系统内已存在该数据源！");
				}

				// 执行添加
				dataSource = new EntityDataSource();
				dataSource.setMinIdleSize(request.getMinIdleSize());
				dataSource.setUserName(request.getUserName());
				dataSource.setDescription(request.getDescription());
				dataSource.setInitialSize(request.getInitialSize());
				dataSource.setType(request.getType());
				dataSource.setJdbcUrl(request.getJdbcUrl());
				dataSource.setPassword(request.getPassword());
				dataSource.setName(request.getName());
				dataSource.setMaxActiveSize(request.getMaxActiveSize());
				dataSource.setTimeoutMillisecond(request.getTimeoutMillisecond());
				Date now = new Date();
				dataSource.setCreatorId(operator.getOperatorId());
				dataSource.setCreateTime(now);
				dataSource.setModifierId(operator.getOperatorId());
				dataSource.setModifyTime(now);
				entityDataSourceMapper.insert(dataSource);
			} catch (Exception e){
				log.error("添加数据源失败", e);
				return methodResult.changeErr("数据源添加失败，系统异常：" + e.getMessage());
			} finally {
				redisService.releaseLock(uniqueKey, requestId);
			}
		}else{
			return methodResult.changeErr("请不要频繁操作！");
		}


		return methodResult;
	}

	/**
	 * 更新数据源
	 * @param operator 操作人
	 * @param dataSourceId 数据源ID
	 * @param request 更新请求
	 * @return 更新结果
	 */
	@Override
	public Result<?> update(Operator operator, long dataSourceId, DataSourceRequest request){
		Result<?> methodResult = new Result<>();

		EntityDataSource entityDataSource = entityDataSourceMapper.selectById(dataSourceId);
		AssertUtils.argumentNull(entityDataSource, "不存在该数据源！");
		String uniqueKey = DATA_SOURCE_UNIQUE_LOCK + (StringUtils.isBlank(request.getName()) ? entityDataSource.getName() : request.getName());
		String requestId = UUID.randomUUID().toString();
		if(redisService.tryLock(uniqueKey, requestId, EXPIRE_ONE_MINUTE)){
			try {
				if(request.getType() > 0 && request.getType() != entityDataSource.getType()){
					entityDataSource.setType(request.getType());
					// 修改了数据源类型
					if(request.getType() == EntityDataSourceTypeEnum.ES.getCode()){
						// 说明原来是MySQL，修改成了ES，需要清空DB中保存的原始MySQL配置信息
						entityDataSource.setJdbcUrl(StringUtils.EMPTY);
						entityDataSource.setInitialSize(0);
						entityDataSource.setMaxActiveSize(0);
						entityDataSource.setMinIdleSize(0);
						entityDataSource.setUserName(StringUtils.EMPTY);
						entityDataSource.setPassword(StringUtils.EMPTY);
					}
				}else{
					// 没有修改数据源类型，则按照已提供的数据更新即可
					entityDataSource.setJdbcUrl(request.getJdbcUrl());
					entityDataSource.setInitialSize(request.getInitialSize());
					entityDataSource.setMaxActiveSize(request.getMaxActiveSize());
					entityDataSource.setMinIdleSize(request.getMinIdleSize());
					entityDataSource.setUserName(request.getUserName());
					entityDataSource.setPassword(request.getPassword());
				}
				if(StringUtils.isNotBlank(request.getName()) && !request.getName().equals(entityDataSource.getName())){
					EntityDataSource existSameNameDataSource = entityDataSourceMapper.selectByName(request.getName());
					if(existSameNameDataSource != null){
						return methodResult.changeErr(String.format("系统内已存在名称为(%s)的数据源！", request.getName()));
					}
				}
				entityDataSource.setName(request.getName());
				entityDataSource.setDescription(request.getDescription());
				entityDataSource.setModifierId(operator.getOperatorId());
				entityDataSource.setModifyTime(new Date());

				entityDataSourceMapper.updateById(entityDataSource);
				// 检查该数据源被哪个场景关联
				searchConfigChangeService.triggerByDataSource(dataSourceId);
			} catch (Exception e) {
				log.error("更新数据源失败", e);
				return methodResult.changeErr("数据源更新失败，系统异常：" + e.getMessage());
			} finally {
				redisService.releaseLock(uniqueKey, requestId);
			}
		}

		return methodResult;
	}

	/**
	 * 删除数据源
	 * @param operator 操作人
	 * @param dataSourceId 数据源ID
	 * @return 删除结果
	 */
	@Override
	public Result<?> delete(Operator operator, long dataSourceId){
		Result<?> methodResult = new Result<>();

		EntityDataSource entityDataSource = entityDataSourceMapper.selectById(dataSourceId);
		if(entityDataSource == null){
			return methodResult.changeErr("该数据源已不存在，无需删除");
		}
		// 查询该数据源是否有引用
		List<EntityTable> entityTables = entityTableMapper.selectByDataSourceId(dataSourceId);
		if(CollectionUtils.isNotEmpty(entityTables)){
			return methodResult.changeErr("存在关联的真实表：" + entityTables.stream().map(input -> String.format("%s(%s)", input.getTableName(), input.getName())).collect(Collectors.joining(", ")));
		}

		// 执行删除
		entityDataSourceMapper.deleteById(dataSourceId);

		return methodResult;
	}

	@Override
	public Result<List<TableDataSourceTreeVO>> allDataSource4Cascade() {
		Result<List<TableDataSourceTreeVO>> methodResult = new Result<>();
		List<TableDataSourceTreeVO> list = Lists.newArrayList();
		List<EntityDataSource> entities = entityDataSourceMapper.selectList(new QueryWrapper<>());
		if(CollectionUtils.isNotEmpty(entities)){
			for (EntityDataSource entity : entities) {
				TableDataSourceTreeVO vo = new TableDataSourceTreeVO();
				vo.setLabel(entity.getName());
				vo.setValue(entity.getId());
				vo.setLeaf(false);
				list.add(vo);
			}
		}
		return methodResult.changeSucc(list);
	}

	@Override
	public Result<String> testConnection(Operator operator, TestConnectionRequest request) {
		return dbMetaService.testConnection(request.getJdbcUrl(), request.getUserName(), request.getPassword());
	}
}
